package edu.ufl.cise.cop5555.sp12.context;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import edu.ufl.cise.cop5555.sp12.ast.Declaration;

@SuppressWarnings("deprecation")
class Value{
	public int scope_number;
	//public ArrayList<String> attributes;
	public Declaration attributes;
	
	public Value()
	{
		
		
		
	}
	
	public Value(int scope_num, Declaration att)
	{
		scope_number = scope_num;
		attributes  = att;
		
		
	}
	public int getScopeNumber()
	{
		return scope_number;
	}
	
	public void setScopeNumber(int scope_n)
	{
		this.scope_number = scope_n;
	}
	
}

public class SymbolTable {

	
	HashMap<String, List<Value>> symbol_table;  
	LinkedList<Integer > scope_stack;
	int current_scope, next_scope;
	@SuppressWarnings("deprecation")
	public SymbolTable(){
     
		symbol_table = new HashMap<String, List<Value>>();
		scope_stack = new LinkedList<Integer>();
		current_scope =0; next_scope = 0;
		
	}


	public void enterScope() {
	current_scope = next_scope++;
	scope_stack.push((Integer)current_scope);
	}
	public void display()
	{
		
		System.out.println("current " + current_scope);
		
	}

	public void exitScope() {
		scope_stack.pop();
		if(!scope_stack.isEmpty())
			current_scope = scope_stack.peek();
		
		
	}

	/*public Declaration getScopeDeclaration(String ident)
	{
		List<Value> list = symbol_table.get(ident);
		
		 if(list != null)
		 {
			Iterator<Value> i = list.iterator();
			int cur_scope;				
			
			while(i.hasNext())
			 {
				 Value val = (Value) i.next();
				//See the scope stack and return the dec which is closest to top of stack
				 if(val.scope_number == current_scope)
					  {
					 	return val.attributes;
					  
					  }
						 
			 }
					
			return null;
		 }
		 else 
		 { return null;
		 
		 }
		
	}*/

	// returns the in-scope declaration of the name if there is one, 
	//otherwise it returns null
	public Declaration lookup(String ident) {
		
	//Lookup ident in symbol table
	List<Value> list = symbol_table.get(ident);
	 if(list != null)
	 {
		Iterator<Value> i = list.iterator();
		Iterator<Integer> s_i = scope_stack.iterator();
		int cur_scope;
	//	int top = scope_stack.peek();
		while(s_i.hasNext()&& s_i!= null)
		{
			cur_scope = (Integer)s_i.next();
			
			 while(i.hasNext())
		 {
			 Value val = (Value) i.next();
			//See the scope stack and return the dec which is closest to top of stack
			 if(val.scope_number == cur_scope)
				  {
				 	return val.attributes;
				  
				  }
					 
		 }
		i = list.iterator();
		}
		return null;
	 }
	 else 
	 { return null;
	 
	 }
	
	
	}
	

	// if the name is already declared IN THE CURRENT SCOPE, returns false. 
	//Otherwise inserts the declaration in the symbol table
	public boolean insert(String ident, Declaration dec) {
		
		//Check to see if the ident is present in the table
		
		
		List<Value> list =  symbol_table.get(ident);
		
		if(list != null ) //no value
		 {
		Iterator i = list.iterator();
		 while(i.hasNext())
		 {
			 Value val = (Value) i.next();
			 if(val.scope_number == current_scope)
			 {
				 return false;
			 }
					 
		 }
		 }
		 Value v = new Value();
		 v.scope_number = current_scope;
		 v.attributes = dec;
		List<Value> newlist =  symbol_table.get(ident);
		if(newlist != null)
			newlist.add(v);
		else
			{newlist = new ArrayList<Value>();
			newlist.add(v);
			}
		
		symbol_table.put(ident, newlist);
				
		 
		return true;
	}


}